package com.chuangke.admin.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chuangke.admin.dao.mapper.SysUserAuditDeptMapper;
import com.chuangke.admin.dto.UserDeptRequest;
import com.chuangke.admin.entity.SysDept;
import com.chuangke.admin.entity.SysUserAuditDept;
import com.chuangke.admin.service.SysDeptService;
import com.chuangke.admin.service.SysUserAuditDeptService;
import com.chuangke.common.constant.CacheKeyConstants;
import com.chuangke.common.idgen.IdManager;

@Service
public class SysUserAuditDeptServiceImpl extends ServiceImpl<SysUserAuditDeptMapper, SysUserAuditDept> implements SysUserAuditDeptService {

	@Autowired
	private SysDeptService sysDeptService;

	@Autowired
	private SysUserAuditDeptMapper sysUserAuditDeptMapper;

	@CacheEvict(cacheNames = CacheKeyConstants.SYS_ROLE_DEPT, key = "'" + CacheKeyConstants.SYS_ROLE_DEPT + "'")
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void save(UserDeptRequest userDeptRequest) {
		sysUserAuditDeptMapper.delete(new QueryWrapper<SysUserAuditDept>().lambda().eq(SysUserAuditDept::getUserId, userDeptRequest.getUserId()).eq(SysUserAuditDept::getRoleId, userDeptRequest.getRoleId()));
		for(SysUserAuditDept sysUserAuditDept:getSysRoleDeptList(userDeptRequest)) {
			sysUserAuditDeptMapper.insert(sysUserAuditDept);
		}
	}
	
	@CacheEvict(cacheNames = CacheKeyConstants.SYS_ROLE_DEPT, key = "'" + CacheKeyConstants.SYS_ROLE_DEPT + "'")
	@Override
	public void remove(String userId, List<String> roleList) {
		if(CollectionUtils.isEmpty(roleList)) {
			return ;
		}
		sysUserAuditDeptMapper.delete(new QueryWrapper<SysUserAuditDept>().lambda().eq(SysUserAuditDept::getUserId, userId).in(SysUserAuditDept::getRoleId, roleList));
	}
	
	@CacheEvict(cacheNames = CacheKeyConstants.SYS_ROLE_DEPT, key = "'" + CacheKeyConstants.SYS_ROLE_DEPT + "'")
	@Override
	public void removeByIds(List<String> ids) {
		super.removeBatchByIds(ids) ;
	}

	private List<SysUserAuditDept> getSysRoleDeptList(UserDeptRequest userDeptRequest) {
		List<SysUserAuditDept> list = new ArrayList<>();
		for (String dept : userDeptRequest.getDeptList()) {
			SysUserAuditDept sysUserDept = new SysUserAuditDept();
			sysUserDept.setUserId(userDeptRequest.getUserId());
			sysUserDept.setRoleId(userDeptRequest.getRoleId());
			sysUserDept.setDeptId(dept);
			sysUserDept.setId(IdManager.nextId());
			list.add(sysUserDept);
		}
		return list;
	}

	@Cacheable(cacheNames = CacheKeyConstants.SYS_ROLE_DEPT, key = "'" + CacheKeyConstants.SYS_ROLE_DEPT + "'")
	@Override
	public Map<String, List<SysUserAuditDept>> findAll() {
		Map<String, SysDept> map = sysDeptService.findMap();
		List<SysUserAuditDept> list = sysUserAuditDeptMapper.selectList(new QueryWrapper<>());
		list.forEach(sysRoleDept -> {
			SysDept sysDept = map.get(sysRoleDept.getDeptId().toString());
			if (sysDept != null) {
				sysRoleDept.setDeptName(sysDept.getName());
			}
		});

		return list.stream()
				.collect(Collectors.groupingBy(roleDept -> roleDept.getUserId() + "-" + roleDept.getRoleId()));
	}

	@Override
	public List<SysUserAuditDept> findByUserRole(String userId, String roleId) {
		Map<String, List<SysUserAuditDept>> map = ((SysUserAuditDeptService) AopContext.currentProxy()).findAll();
		return map == null ? new ArrayList<>() : map.get(userId + "-" + roleId);
	}
	
	@Override
	public List<SysUserAuditDept> findByUserRole(String userId) {
		Map<String, List<SysUserAuditDept>> map = ((SysUserAuditDeptService) AopContext.currentProxy()).findAll();
		List<SysUserAuditDept> list = new ArrayList<>() ;
		map.keySet().forEach(key->{
			if(key.startsWith(userId+"-")) {
				list.addAll(map.get(key)) ;
			}
		});
		return list.stream().filter(sysRoleDept-> userId.equals(sysRoleDept.getUserId())).collect(Collectors.toList());
	}

	@Override
	public List<SysUserAuditDept> findUserByRoleDept(String roleId, String deptId) {
		List<SysUserAuditDept> roleDeptList = new ArrayList<>();

		Map<String, List<SysUserAuditDept>> map = ((SysUserAuditDeptService) AopContext.currentProxy()).findAll();
		if (map.isEmpty()) {
			return roleDeptList;
		}

		List<SysUserAuditDept> allRoleDept = new ArrayList<>();
		for (List<SysUserAuditDept> list : map.values()) {
			allRoleDept.addAll(list);
		}

		for (SysUserAuditDept roleDept : allRoleDept) {
			if (roleDept.getDeptId().equals(deptId) && roleDept.getRoleId().equals(roleId)) {
				roleDeptList.add(roleDept);
			}
		}

		return roleDeptList;
	}

	@Override
	public List<SysDept> findUserDeptWithChildren(String userId, String roleId) {
		List<SysDept> sysDeptList = sysDeptService.findListWithChildren();
		Map<String, SysDept> sysDeptMap = sysDeptList.stream().collect(Collectors.toMap(SysDept::getId, a -> a));
		Map<String, List<SysUserAuditDept>> map = ((SysUserAuditDeptService) AopContext.currentProxy()).findAll();
		List<SysUserAuditDept> userDeptList = map == null ? new ArrayList<>() : map.get(userId + "-" + roleId);
		List<SysDept> userDeptListWithChildren = new ArrayList<>();

		if(userDeptList == null) {
			return  userDeptListWithChildren ;
		}
		
		for (SysUserAuditDept userDept : userDeptList) {
			SysDept dept = sysDeptMap.get(userDept.getDeptId());
			userDeptListWithChildren.add(dept);
			if (!CollectionUtils.isEmpty(dept.getChildren())) {
				v1(userDeptListWithChildren, dept.getChildren());
			}
		}
		return userDeptListWithChildren;
	}

	private void v1(List<SysDept> userDeptListWithChildren, List<SysDept> deptList) {
		for (SysDept dept : deptList) {
			userDeptListWithChildren.add(dept);
			if (!CollectionUtils.isEmpty(dept.getChildren())) {
				v1(userDeptListWithChildren, dept.getChildren());
			}
		}
	}

	@Override
	public boolean exists(String userId, String roleId, String deptId) {
		Map<String, List<SysUserAuditDept>> map = ((SysUserAuditDeptService) AopContext.currentProxy()).findAll();
		List<SysUserAuditDept> list = map.get(userId + "-" + roleId);
		return list != null && list.stream().map(SysUserAuditDept::getDeptId).collect(Collectors.toList()).contains(deptId);
	}

	@CacheEvict(cacheNames = CacheKeyConstants.SYS_ROLE_DEPT, key = "'" + CacheKeyConstants.SYS_ROLE_DEPT + "'")
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveBatchAuditRule(List<SysUserAuditDept> list) {
		this.saveBatch(list);
	}

	@CacheEvict(cacheNames = CacheKeyConstants.SYS_ROLE_DEPT, key = "'" + CacheKeyConstants.SYS_ROLE_DEPT + "'")
	@Override
	public void removeAuditRule(LambdaQueryWrapper<SysUserAuditDept> lambdaQueryWrapper) {
		this.remove(lambdaQueryWrapper);
	}

	@Override
	public void deleteByUserId(String userId) {
		sysUserAuditDeptMapper.delete(new QueryWrapper<SysUserAuditDept>().lambda().eq(SysUserAuditDept::getUserId, userId));
	}

}
